package com.authine.cloudpivot.ext.service.voucher.impl;

import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.ext.Enum.BillType;
import com.authine.cloudpivot.ext.constants.AppConst;
import com.authine.cloudpivot.ext.constants.KingDeeConstant;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.constants.PlatformConst;
import com.authine.cloudpivot.ext.dto.BillFeeDto;
import com.authine.cloudpivot.ext.dto.kingDee.request.*;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceApply;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceDetail;
import com.authine.cloudpivot.ext.dto.pm.RecordingVoucherDTO;
import com.authine.cloudpivot.ext.dto.pm.RecordingVoucherDTO2;
import com.authine.cloudpivot.ext.dto.query.RecordingVoucherQuery;
import com.authine.cloudpivot.ext.dto.voucher.KingDeeBasicStats;
import com.authine.cloudpivot.ext.dto.voucher.Voucher;
import com.authine.cloudpivot.ext.enums.kingdee.BusinessType;
import com.authine.cloudpivot.ext.enums.kingdee.KingDeeBasicStatsEnum;
import com.authine.cloudpivot.ext.kingdee.work.OtherWork;
import com.authine.cloudpivot.ext.service.InvoiceVoucherService;
import com.authine.cloudpivot.ext.service.KingDeeBasicStatsService;
import com.authine.cloudpivot.ext.service.OtherVoucherService;
import com.authine.cloudpivot.ext.service.VoucherService;
import com.authine.cloudpivot.ext.service.voucher.RecordingVoucherPmService;
import com.authine.cloudpivot.ext.utils.BoResultFormat;
import com.authine.cloudpivot.ext.utils.JdbcTemplateUtils;
import com.authine.cloudpivot.ext.utils.RecordingVoucherPmUtil;
import com.authine.cloudpivot.ext.utils.StringUtils;
import com.authine.common.json.JsonUtils;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.dto.bo.response.BOList;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: liwei
 * @DateTime: 2021/7/27
 * @Description: TODO
 */
@Slf4j
public class RecordingVoucherPmServiceImpl implements RecordingVoucherPmService {

    public static final String ERROR = "传参异常——";
    private NamedParameterJdbcTemplate jdbcTemplate = ApplicationContextUtils.getBean(NamedParameterJdbcTemplate.class);
    private InvoiceVoucherService invoiceVoucherService = new InvoiceVoucherService();
    private OtherVoucherService otherVoucherService = new OtherVoucherService();
    private VoucherService voucherService = new VoucherService();
    private RecordingVoucherPmUtil recordingVoucherPmUtil = new RecordingVoucherPmUtil();
    private KingDeeBasicStatsService kingDeeBasicStatsService = new KingDeeBasicStatsService();


    @Override
    public SingleResponse deleteRecordingVoucherByIds(List<String> ids) {
        log.info("deleteRecordingVoucherByIds  request:{}", ids);

        SingleResponse singleResponse = otherVoucherService.deleteRecordingVoucherByIds(ids);
        log.info("deleteRecordingVoucherByIds  End of  logic processing <<<");

        return singleResponse;
    }

    @Override
    public String saveRecordingAndInvoice(List<RecordingVoucherDTO> recordingVoucherDTOList) {
        log.info("saveRecordingAndInvoice  request:{}", recordingVoucherDTOList);

        Assert.isTrue(!CollectionUtils.isEmpty(recordingVoucherDTOList), "开发票凭证记录数据不能为空");

        List<String> businessIds = recordingVoucherDTOList.stream().map(e -> e.getBusinessId()).collect(Collectors.toList());
        List<String> ids = recordingVoucherDTOList.stream().map(e -> e.getId()).collect(Collectors.toList());

        List<Map<String, Object>> recordVoucherList = JdbcTemplateUtils.builder(ModelConst.T_RECORD_VOUCHER).selectField(" * ").in(KingDeeConstant.ID_FIELD, ids).queryForList();
        Assert.isTrue(!CollectionUtils.isEmpty(recordVoucherList), " 未找到开发票凭证记录数据！！！");

        Map<String, Map<String, Object>> recordVoucherListMap = recordVoucherList.stream().collect(Collectors.toMap(x -> String.valueOf(x.get("id")), y -> y));

        recordingVoucherDTOList.forEach(e -> {

            //根据id获取发票信息 金蝶原先代码 有很多 数据装载逻辑，但是装载数据在当前逻辑中并未使用
            InvoiceApply invoiceApply = recordingVoucherPmUtil.getInvoiceApply(e.getBusinessId());
            Assert.notNull(invoiceApply, "开票申请单不能为空");

            Map<String, Object> recordVoucher = recordVoucherListMap.get(e.getId());
            Assert.notNull(invoiceApply, "凭证记录数据不能为空");
            String businessType = recordVoucher.get("business_type").toString();

            //根据 开票数据状态确定生成对应哪种凭证
            if (businessType.equals(BusinessType.PlatformCustomerInvoice.name()) || businessType.equals(BusinessType.GoldenTaxInvoice.name())) {
                //开普通票
                KingDeeInvoiceApply kingDeeInvoiceApply = recordingVoucherPmUtil.createOrUpdateInvoiceVoucher(invoiceApply, e.getKingdeeCode());

                Assert.notNull(kingDeeInvoiceApply, "金蝶请求参数不能为空");

                invoiceVoucherService.createInvoiceVoucher(kingDeeInvoiceApply);
                otherVoucherService.deleteRecordingVoucherById(e.getId());
            }

            if (businessType.equals(BusinessType.PlatformCustomerRedInvoice.name())) {
                //开红票
                KingDeeRedInvoiceApply kingDeeRedInvoiceApply = recordingVoucherPmUtil.createOrUpdateRedInvoiceVoucher(invoiceApply, e.getKingdeeCode());

                Assert.notNull(kingDeeRedInvoiceApply, "金蝶请求参数不能为空");

                invoiceVoucherService.createRedInvoiceVoucher(kingDeeRedInvoiceApply);
                otherVoucherService.deleteRecordingVoucherById(e.getId());
            }

        });
        log.info("saveRecordingAndInvoice  End of  logic processing <<<");

        return "success";
    }

    @Override
    public String saveServiceFeeInvoice(List<RecordingVoucherDTO2> recordingVoucherDTO2s) {
        log.info("saveServiceFeeInvoice  request:{}", recordingVoucherDTO2s);

        Assert.isTrue(null != recordingVoucherDTO2s && recordingVoucherDTO2s.size() > 0, "开服务费凭证记录数据不能为空");

        // 凭证记录 id集合
        List<String> idList = recordingVoucherDTO2s.stream().map(RecordingVoucherDTO2::getId).collect(Collectors.toList());
        // 凭证记录 业务id集合
        List<String> businessList = recordingVoucherDTO2s.stream().map(RecordingVoucherDTO2::getBusinessId).collect(Collectors.toList());

        // 根据发票申请单id集合，获取发票申请单集合
        List<InvoiceApply> invoiceApplyList = recordingVoucherPmUtil.getInvoiceApplyListByIds(businessList);
        Assert.notNull(invoiceApplyList, "根据业务id集合，获取发票数据集合不能为空");

        //重新 根据发票号 排序
        invoiceApplyList = invoiceApplyList.stream().sorted(Comparator.comparing(InvoiceApply::getNumber)).collect(Collectors.toList());

        String numbers = "";
        for (InvoiceApply invoiceApply : invoiceApplyList) {

            BigDecimal amount = BigDecimal.ZERO;
            BigDecimal pretaxInterest = BigDecimal.ZERO;
            BigDecimal pretaxPlatform = BigDecimal.ZERO;

            amount = amount.add(invoiceApply.getTotal());

            List<BillFeeDto> billFeeList = recordingVoucherPmUtil.getServiceInvoiceAndGoodsInvoice(invoiceApply.getId());
            Assert.isTrue(null != billFeeList && billFeeList.size() > 0, "根据申请单id集合，获取账单服务费数据集合不能为空");

            List<String> goodsNumbers = new ArrayList<>();
            for (BillFeeDto billFeeDto : billFeeList) {

                BigDecimal divide = billFeeDto.getTotal().divide(billFeeDto.getTax_rate().add(BigDecimal.ONE), 11);

                BigDecimal total = divide.divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);

                if (billFeeDto.getType().equals(BillType.FinancialFee)) {

                    pretaxInterest = pretaxInterest.add(total);
                } else {
                    pretaxPlatform = pretaxPlatform.add(total);
                }

                goodsNumbers.add(billFeeDto.getGoods_invoice_number());
            }

            //todo 因金税反写的只是单上的未税金额 导致平台计算服务费 和 金融服务费有尾差 以下调整 为避免因尾差（0.01-0.03） 做凭证借贷不等情况

            if (pretaxInterest.compareTo(BigDecimal.ZERO) != 0 && pretaxPlatform.compareTo(BigDecimal.ZERO) != 0) {
                //金融费 != 0 && 服务费 != 0  服务费 = 发票申请单的未税金额 - 金融费
                pretaxPlatform = invoiceApply.getPrice_amount().subtract(pretaxInterest);
            } else if (pretaxInterest.compareTo(BigDecimal.ZERO) != 0 && pretaxPlatform.compareTo(BigDecimal.ZERO) == 0) {
                //金融费 != 0  && 服务费 == 0  金融费 = 发票申请单的未税金额
                pretaxInterest = invoiceApply.getPrice_amount();
            } else {
                //其他情况 金融服务费 == 0 && 服务费 != 0 服务费 = 发票申请单的未税金额
                pretaxPlatform = invoiceApply.getPrice_amount();
            }

            goodsNumbers = goodsNumbers.size() > 0 ? goodsNumbers.subList(0, 1) : goodsNumbers;
            numbers = String.join(",", goodsNumbers);

            KingDeeServiceFeeInvoice kingDeeServiceFeeInvoice = KingDeeServiceFeeInvoice.builder()
                    .id(invoiceApply.getId())
                    .organizationId(invoiceApply.getPurchase_organization_id().getId())
                    .orgCompanyName(invoiceApply.getPurchase_organization_name())
                    .amount(amount)
                    .pretaxInterest(pretaxInterest)
                    .pretaxPlatform(pretaxPlatform)
                    .number(invoiceApply.getNumber())
                    .taxPayable(invoiceApply.getTax_amount())
                    .purchaseInvoiceNumber(numbers)
                    .accountName(invoiceApply.getAccount_name()).build();

            invoiceVoucherService.createFeeInvoiceVoucher(kingDeeServiceFeeInvoice);
        }

        otherVoucherService.deleteRecordingVoucherByIds(idList);
        log.info("saveServiceFeeInvoice  End of  logic processing <<<");

        return "success";
    }


    @Override
    public String saveRedServiceFeeInvoice(List<RecordingVoucherDTO2> recordingVoucherDTO2s) {
        log.info("saveRedServiceFeeInvoice  request:{}", recordingVoucherDTO2s);

        Assert.isTrue(null != recordingVoucherDTO2s && recordingVoucherDTO2s.size() > 0, "开服务费红票凭证记录数据不能为空");

        // 凭证记录 id集合
        List<String> idList = recordingVoucherDTO2s.stream().map(RecordingVoucherDTO2::getId).collect(Collectors.toList());
        // 凭证记录 业务id集合
        List<String> businessList = recordingVoucherDTO2s.stream().map(RecordingVoucherDTO2::getBusinessId).collect(Collectors.toList());

        // 根据发票申请单id集合，获取发票申请单集合
        List<InvoiceApply> invoiceApplyList = recordingVoucherPmUtil.getInvoiceApplyListByIds(businessList);

        Assert.isTrue(null != invoiceApplyList && invoiceApplyList.size() > 0, "根据业务id集合，获取发票数据集合不能为空");

        //重新 根据发票号 排序
        invoiceApplyList = invoiceApplyList.stream().sorted(Comparator.comparing(InvoiceApply::getNumber)).collect(Collectors.toList());

        for (InvoiceApply invoiceApply : invoiceApplyList) {

            BigDecimal pretaxInterest = BigDecimal.ZERO;
            BigDecimal pretaxPlatform = BigDecimal.ZERO;

            List<BillFeeDto> billFeeList = recordingVoucherPmUtil.getServiceInvoiceAndGoodsInvoice(invoiceApply.getId());

            Assert.isTrue(null != billFeeList && billFeeList.size() > 0, "根据申请单id集合，获取账单服务费数据集合不能为空");

            for (BillFeeDto billFeeDto : billFeeList) {

                BigDecimal divide = billFeeDto.getTotal().divide(billFeeDto.getTax_rate().add(BigDecimal.ONE), 11);

                BigDecimal total = divide.divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);

                if (billFeeDto.getType().equals(BillType.FinancialFee)) {

                    pretaxInterest = pretaxInterest.add(total);
                } else {
                    pretaxPlatform = pretaxPlatform.add(total);
                }
            }

            //todo 因金税反写的只是单上的未税金额 导致平台计算服务费 和 金融服务费有尾差 以下调整 为避免因尾差（0.01-0.03） 做凭证借贷不等情况

            if (pretaxInterest.compareTo(BigDecimal.ZERO) != 0 && pretaxPlatform.compareTo(BigDecimal.ZERO) != 0) {
                //金融费 != 0 && 服务费 != 0  服务费 = 发票申请单的未税金额 - 金融费
                pretaxPlatform = invoiceApply.getPrice_amount().subtract(pretaxInterest);
            } else if (pretaxInterest.compareTo(BigDecimal.ZERO) != 0 && pretaxPlatform.compareTo(BigDecimal.ZERO) == 0) {
                //金融费 != 0  && 服务费 == 0  金融费 = 发票申请单的未税金额
                pretaxInterest = invoiceApply.getPrice_amount();
            } else {
                //其他情况 金融服务费 == 0 && 服务费 != 0 服务费 = 发票申请单的未税金额
                pretaxPlatform = invoiceApply.getPrice_amount();
            }

            InvoiceApply offsetInvoiceApply = recordingVoucherPmUtil.getInvoiceApply(invoiceApply.getOffset_id());

            Assert.notNull(offsetInvoiceApply, "未获取到对应的货物蓝字发票单 ！！！");

            KingDeeServiceFeeRedInvoice kingDeeServiceFeeRedInvoice = KingDeeServiceFeeRedInvoice.builder()
                    .id(invoiceApply.getId())
                    .orgId(invoiceApply.getPurchase_organization_id().getId())
                    .orgCompanyName(invoiceApply.getPurchase_organization_name())
                    .amount(invoiceApply.getTotal().negate())
                    .pretaxInterest(pretaxInterest.negate())
                    .pretaxPlatform(pretaxPlatform.negate())
                    .number(invoiceApply.getNumber())
                    .taxPayable(invoiceApply.getTax_amount().negate())
                    .oldNumber(offsetInvoiceApply.getNumber())
                    .accountName(null).build();

            invoiceVoucherService.createFeeRedInvoiceVoucher(kingDeeServiceFeeRedInvoice);

        }
        otherVoucherService.deleteRecordingVoucherByIds(idList);
        log.info("saveRedServiceFeeInvoice  End of  logic processing <<<");
        return "success";
    }

    @Override
    public Integer pushVoucher(List<Voucher> voucher) {
        log.info("pushVoucher  request:{}", voucher);

        SingleResponse<Integer> integerSingleResponse = voucherService.pushVoucher(voucher);
        log.info("pushVoucher  End of  logic processing <<<");

        return 1;
    }

    @Override
    public SingleResponse<List<KingDeeBasicStats>> listByCompanyName(KingDeeBasicRequest request) {
        return kingDeeBasicStatsService.listByCompanyName(request);
    }

    @Override
    public SingleResponse<List<String>> saveKingDeeBasicStats(List<KingDeeBasicStats> params) {
        Assert.notNull(params,"保存金蝶基础数据列表不能为空！！！");
        params.stream().forEach(e->e.setInfo_type(KingDeeBasicStatsEnum.Customer));
        return kingDeeBasicStatsService.saveBatch(params);
    }

    @Override
    public SingleResponse updateKingDeeBasicStats(KingDeeBasicStats param) {
        return kingDeeBasicStatsService.update(param);
    }


    public SingleResponse<BOList> listRecordingVoucher(RecordingVoucherQuery query) {
        log.info("------------------------凭证记录-列表 listRecordingVoucher query：{}------------------------", JSONObject.toJSONString(query));
        if (null == query.getPageIndex() || null == query.getPageSize()) {
            return SingleResponse.buildFailure("-1", "pageIndex、pageSize必填");
        }

        String recordVoucherT = JdbcTemplateUtils.getTableName(ModelConst.T_RECORD_VOUCHER);
        Map<String, Object> parameter = new HashMap<>();
        StringBuilder listSql = new StringBuilder();
        StringBuilder whereSql = new StringBuilder();
        StringBuilder countSql = new StringBuilder();

        listSql.append("select rv.* from " + recordVoucherT + " rv  where rv.deleted ='0'");
        countSql.append("select count(*) from " + recordVoucherT + " rv  where rv.deleted ='0'");
        //拼接参数
        //凭证ID
        if (StringUtils.isNotBlank(query.getVoucherId())) {
            List<String> voucher_ids = StringUtils.stringToListString(query.getVoucherId(), ";");
            whereSql.append(" and rv.voucher_id in (:voucher_ids) ");
            parameter.put("voucher_ids", voucher_ids);
        }
        //业务ID
        if (StringUtils.isNotBlank(query.getBusinessId())) {
            List<String> business_ids = StringUtils.stringToListString(query.getBusinessId(), ";");
            whereSql.append(" and rv.business_id in (:business_ids) ");
            parameter.put("business_ids", business_ids);
        }
        //发票号码
        if (StringUtils.isNotBlank(query.getNumber())) {
            List<String> invoice_nos = StringUtils.stringToListString(query.getNumber(), ";");
            whereSql.append(" and rv.invoice_no in (:invoice_nos) ");
            parameter.put("invoice_nos", invoice_nos);
        }
        //平台组织名称
        if (StringUtils.isNotBlank(query.getAccountName())) {
            whereSql.append(" and rv.account_name = :account_name ");
            parameter.put("account_name", query.getAccountName());
        }
        //业务类型
        if (StringUtils.isNotBlank(query.getBusinessType())) {
            whereSql.append(" and rv.business_type = :business_type ");
            parameter.put("business_type", query.getBusinessType());
        }
        //是否成功
        if (null != query.getIsSuccess()) {
            whereSql.append(" and rv.is_success = :is_success ");
            parameter.put("is_success", query.getIsSuccess());
        }
        //创建时间
        if (StringUtils.isNotBlank(query.getStartCreatedTime()) && StringUtils.isNotBlank(query.getEndCreatedTime())) {
            whereSql.append(" and rv.createdTime between :startTime and :endTime ");
            parameter.put("startTime", query.getStartCreatedTime());
            parameter.put("endTime", query.getEndCreatedTime());
        }

        countSql.append(whereSql);
        listSql.append(whereSql);

        if (null != query.getSort() && !query.getSort().isEmpty() && query.getSort().equals("ASC")) {
            listSql.append(" order by rv.invoice_no asc");
        } else {
            listSql.append(" order by rv.id desc");
        }

        listSql.append(" limit " + query.getPageIndex() * query.getPageSize() + ", " + query.getPageSize());
        log.info("------------------------凭证记录-列表 listRecordingVoucher listSql：{}------------------------parameter：{}", listSql, JsonUtils.toJson(parameter));
        List<Map<String, Object>> resultList = jdbcTemplate.queryForList(listSql.toString(), parameter);
        Integer count = 0;
        try {
            count = jdbcTemplate.queryForObject(countSql.toString(), parameter, Integer.class);
        } catch (DataAccessException e) {
            e.printStackTrace();
        }

        //构建结果集
        BoResultFormat.resultFormat(resultList, ModelConst.T_RECORD_VOUCHER);
        BOList bOList = new BOList();
        bOList.setData(resultList);
        bOList.setTotal(count);
        bOList.setSchemaCode(ModelConst.T_RECORD_VOUCHER);

        return  SingleResponse.of(bOList);
    }

    @Override
    public SingleResponse<String> saveDimension(KingDeeBasicStats param) {
        String save = kingDeeBasicStatsService.save(param);
        return SingleResponse.of(save);
    }
}
